package questions;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 可重入锁：
 * <b>同一线程</b> 中当外层代码获得了锁，可以进入内部带锁的代码块
 * <p>
 * synchronized和ReentrantLock是典型的可重入锁
 */
public class ReentrantLockDemo {

    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(() -> {
            phone.sendMsg();
        }, "t1").start();
        new Thread(() -> {
            phone.sendMsg();
        }, "t2").start();
        TimeUnit.SECONDS.sleep(2);
        System.out.println();
        System.out.println();
        System.out.println();
        System.out.println();
        System.out.println();
        ReentrantLockPhone reentrantLockPhone = new ReentrantLockPhone();
        new Thread(() -> {
            reentrantLockPhone.sendMsg();
        }, "t3").start();
        new Thread(() -> {
            reentrantLockPhone.sendMsg();
        }, "t4").start();
    }

}

/**
 * 进入sendMsg获得了锁，还能进入当前线程的sendMail方法，并获得锁
 */
class ReentrantLockPhone {
    ReentrantLock reentrantLock = new ReentrantLock();

    public void sendMsg() {
        reentrantLock.lock();
        reentrantLock.lock();
        System.out.println(Thread.currentThread().getName() + "发送Msg");
        sendMail();
        reentrantLock.unlock();
        reentrantLock.unlock();
    }

    public void sendMail() {
        reentrantLock.lock();
        System.out.println(Thread.currentThread().getName() + "发送Mail");
        reentrantLock.unlock();
    }
}

class Phone {

    public synchronized void sendMsg() {
        System.out.println(Thread.currentThread().getName() + "发送Msg");
        sendMail();
    }

    public synchronized void sendMail() {
        System.out.println(Thread.currentThread().getName() + "发送Mail");
    }
}
